package com.huike.clues.service.impl;

import com.huike.clues.domain.*;
import com.huike.clues.domain.vo.ImportDataVO;
import com.huike.clues.domain.vo.TbClueExcelVo;
import com.huike.clues.mapper.*;
import com.huike.clues.service.ITbClueService;
import com.huike.clues.utils.HuiKeCrmDateUtils;
import com.huike.clues.utils.JobUtils;
import com.huike.common.constant.Constants;
import com.huike.common.core.domain.entity.SysUser;
import com.huike.common.exception.CustomException;
import com.huike.common.utils.DateUtils;
import com.huike.common.utils.SecurityUtils;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author EthanRuins
 * @date 2023/7/12
 * @apiNote
 */
@Service
@AllArgsConstructor
public class TbClueServiceImpl implements ITbClueService {
    private final SysUserMapper userMapper;
    private final SysDictDataMapper sysDictDataMapper;
    private final TbClueMapper clueMapper;
    private final TbClueTrackRecordMapper clueTrackRecordMapper;
    private final TbActivityMapper activityMapper;
    private final TbAssignRecordMapper assignRecordMapper;
    private final TbRulePoolMapper rulePoolMapper;

    /**
     * 新增线索
     *
     * @param clue 线索
     * @return 影响行数
     */
    @Override
    @Transactional
    public int insert(TbClue clue) {
        clueMapper.insert(clue);
        TbAssignRecord assignRecord = new TbAssignRecord();
        assignRecord.setAssignId(clue.getId());
        assignRecord.setUserName(SecurityUtils.getUsername());
        assignRecord.setDeptId(SecurityUtils.getDeptId());
        int rows = assignRecordMapper.insert(assignRecord);
        Date endDate = HuiKeCrmDateUtils.getEndDateByRule(assignRecord);
        clueMapper.updateClueEndTimeById(endDate, clue.getId());
        return rows;
    }

    /**
     * 修改线索管理
     *
     * @param clue 线索数据
     * @return 影响行数
     */
    @Override
    public int update(TbClue clue) {
        return clueMapper.update(clue);
    }

    /**
     * 批量分配线索
     *
     * @param ids    线索ID
     * @param userId 用户ID
     * @return 分配结果
     */
    @Override
    @Transactional
    public String assign(Long[] ids, Long userId) {
        TbRulePool rulePool = rulePoolMapper.getRule(Constants.rule_type_clue);
        int assignRecords = assignRecordMapper.countAssignCluesByUser(userId);
        if (assignRecords > rulePool.getMaxNunmber()) {
            throw new CustomException("分配失败！最大保有量(" + rulePool.getMaxNunmber() + ")，剩余可以分配" + (rulePool.getMaxNunmber() - assignRecords) + "条线索");
        }

        for (int i = 0; i < ids.length; i++) {
            Long clueId = ids[i];
            if (assignRecords + i > rulePool.getMaxNunmber()) {
                throw new CustomException("分配失败！保有量达到上线，最多选择" + rulePool.getMaxNunmber() + "条线索");
            }
            updateStatus(clueId, TbClue.StatusType.UNFOLLOWED.getValue());
            TbAssignRecord tbAssignRecord = addNewRecord(clueId, userId);
            Date endDate = HuiKeCrmDateUtils.getEndDateByRule(tbAssignRecord);
            clueMapper.updateClueEndTimeById(endDate, clueId);
        }
        return "全部分配";
    }

    /**
     * 批量捞取线索
     *
     * @param ids    线索ID
     * @param userId 捞取人ID
     * @return 捞取结果
     */
    @Override
    public String gain(Long[] ids, Long userId) {
        TbRulePool rulePool = rulePoolMapper.getRule(Constants.rule_type_clue);
        boolean isBatch = ids.length > 1;
        int assignRecords = assignRecordMapper.countAssignCluesByUser(userId);
        if (assignRecords >= rulePool.getMaxNunmber()) {
            throw new CustomException("捞取失败！最大保有量(" + rulePool.getMaxNunmber() + ")，剩余可以捞取" + (rulePool.getMaxNunmber() - assignRecords) + "条线索");
        }

        for (int i = 0; i < ids.length; i++) {
            Long clueId = ids[i];
            if (assignRecords + i > rulePool.getMaxNunmber()) {
                throw new CustomException("捞取失败！保有量达到上限，最多选择" + (rulePool.getMaxNunmber() - assignRecords) + "条线索");
            }
            TbAssignRecord assignRecord = assignRecordMapper.getByAssignId(clueId, TbAssignRecord.RecordType.CLUES.getValue());
            if (assignRecord != null && Objects.equals(assignRecord.getUserId(), userId)) {
                Date repeatGetTime = JobUtils.getDate(rulePool.getRepeatGetTime().intValue(), rulePool.getRepeatType(), assignRecord.getCreateTime());
                if (DateUtils.getNowDate().before(repeatGetTime)) {
                    if (isBatch) {
                        continue;
                    } else {
                        throw new CustomException("捞取失败！需要在 " + DateUtils.dateTimeHm(repeatGetTime) + " 后捞取");
                    }
                }
            }
            clueMapper.updateNextTimeAndStatus(clueId, TbClue.StatusType.UNFOLLOWED.getValue());
            TbAssignRecord tbAssignRecord = addNewRecord(clueId, userId);
            Date endDate = HuiKeCrmDateUtils.getEndDateByRule(tbAssignRecord);
            clueMapper.updateClueEndTimeById(endDate, clueId);
        }
        return "全部捞取成功";
    }

    /**
     * 伪线索
     *
     * @param clueId 线索ID
     * @param reason 伪线索原因
     * @param remark 标注
     * @return 影响行数
     */
    @Override
    @Transactional
    public int falseClue(Long clueId, String reason, String remark) {
        TbClue clue = clueMapper.getById(clueId);
        int falseCount = clue.getFalseCount();
        if (falseCount > 3) {
            return clueMapper.deleteById(clueId);
        }
        clue.setFalseCount(clue.getFalseCount() + 1);
        clue.setStatus(TbClue.StatusType.FALSE.getValue());
        update(clue);
        updateStatus(clueId, TbClue.StatusType.FALSE.getValue());

        TbClueTrackRecord clueTrackRecord = new TbClueTrackRecord();
        clueTrackRecord.setFalseReason(reason);
        clueTrackRecord.setRecord(remark);
        clueTrackRecord.setClueId(clueId);
        clueTrackRecord.setType("1");
        return clueTrackRecordMapper.insert(clueTrackRecord);
    }

    /**
     * 导入线索数据
     *
     * @param data 读取到的每行数据
     * @return 影响行数
     */
    @Override
    public ImportDataVO importCluesData(TbClueExcelVo data) {
        TbClue clue = new TbClue();
        // 活动编号不存在则返回错误
        TbActivity activity = activityMapper.getByCode(data.getActivityCode());
        if (activity == null) {
            return ImportDataVO.error();
        }
        clue.setActivityId(activity.getId());

        // 手机号和渠道
        if (data.getPhone() == null || data.getChannel() == null) {
            return ImportDataVO.error();
        }
        clue.setName(data.getName());

        // 字典值替换
        clue.setSubject(sysDictDataMapper.selectDictValue("course_subject", data.getSubject()));
        clue.setSex(sysDictDataMapper.selectDictValue("sys_user_sex", data.getSex()));
        clue.setLevel(sysDictDataMapper.selectDictValue("clues_level", data.getLevel()));
        clue.setChannel(sysDictDataMapper.selectDictValue("clues_item", data.getChannel()));
        clue.setPhone(data.getPhone());
        clue.setStatus(TbClue.StatusType.UNFOLLOWED.getValue());
        clueMapper.insert(clue);

        // 统一由Admin分配
        SysUser admin = userMapper.selectUserByUserName("admin");
        TbAssignRecord assignRecord = new TbAssignRecord();
        assignRecord.setAssignId(clue.getId());
        assignRecord.setUserId(admin.getUserId());
        assignRecord.setUserName(admin.getUserName());
        assignRecord.setDeptId(admin.getDeptId());
        assignRecordMapper.insert(assignRecord);

        return ImportDataVO.success();
    }

    private TbAssignRecord addNewRecord(Long clueId, Long userId) {
        assignRecordMapper.updateLatest(clueId, TbAssignRecord.RecordType.CLUES.getValue());

        TbAssignRecord assignRecord = new TbAssignRecord();
        assignRecord.setAssignId(clueId);
        SysUser user = userMapper.selectUserById(userId);
        assignRecord.setUserId(userId);
        assignRecord.setUserName(user.getUserName());
        assignRecord.setDeptId(user.getDeptId());
        assignRecord.setType(TbAssignRecord.RecordType.CLUES.getValue());
        assignRecordMapper.insert(assignRecord);
        return assignRecord;
    }

    /**
     * 根据线索ID更新状态
     *
     * @param clueId 线索ID
     * @param status 状态
     * @return 影响行数
     */
    @Override
    @Transactional
    public int updateStatus(Long clueId, String status) {
        return clueMapper.updateNextTimeAndStatus(clueId, status);
    }

    /**
     * 根据ID获取线索数据，需判断是否是待分配数据
     *
     * @param id 线索ID
     * @return 线索数据
     */
    @Override
    public TbClue getById(Long id) {
        TbClue clue = clueMapper.getById(id);
        if (clue != null && clue.getActivityId() != null) {
            TbActivity activity = activityMapper.getById(clue.getActivityId());
            if (activity != null) {
                clue.setActivityInfo(activity.getCode() + ":" + activity.getName() + ":" + activity.getInfo());
            }
        }
        TbAssignRecord assignRecord = assignRecordMapper.getByAssignId(Objects.requireNonNull(clue).getId(), "0");
        // 线索是待分配数据
        if (assignRecord == null) {
            return clue;
        }
        // 不是待分配数据
        clue.setOwner(assignRecord.getUserName());
        clue.setOwnerTime(assignRecord.getCreateTime());
        return clue;
    }

    /**
     * 根据指定条件查询线索列表
     * @param clue 线索条件
     * @return 线索列表
     */
    @Override
    public List<TbClue> getClueList(TbClue clue) {
        return clueMapper.getClueList(clue);
    }

    /**
     * 根据指定条件查询线索池列表，如果存在关联的活动，需填充相应活动的名称
     *
     * @param clue 线索条件
     * @return 线索池列表
     */
    @Override
    public List<TbClue> getCluePool(TbClue clue) {
        List<TbClue> cluePool = clueMapper.getCluePool(clue);
        for (TbClue tbClue : cluePool) {
            if (tbClue.getActivityId() != null) {
                TbActivity activity = activityMapper.getById(tbClue.getActivityId());
                if (activity != null) {
                    tbClue.setActivityName(activity.getName());
                }
            }
        }
        return cluePool;
    }

    /**
     * 检验手机号是否唯一
     *
     * @param phone 手机号
     * @return true-手机号存在  false-手机号不存在
     */
    @Override
    public boolean checkPhoneUnique(String phone) {
        TbClue byPhone = clueMapper.getByPhone(phone);
        return byPhone != null;
    }
}
